﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NasuTek.Shion.Extencibility;
using NasuTek.Shion.Agent;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Shion.Lua
{
    public class Plugin : IPlugin
    {
        public static LuaEngine engine;
        #region IPlugin Members
        ExtencibilityManager ex;
        public void Load(ExtencibilityManager e)
        {
            ex = e;
            e.Plugins.Add("Lua Engine", new ExtencibilityManager.PluginData("Lua Engine",
                "(C) 2009 NasuTek Systems",
                "NasuTek Systems",
                "Gives a Lua Hook to create Lua Shion 6 Scripts",
                GetType().Assembly.GetName().Version));

            engine = new LuaEngine(e);
            e.OnMessage.Add("LuaEngine", new HookLuaToOns());
            e.OnNotice.Add("LuaEngine", new HookLuaToOns());
            e.OnAction.Add("LuaEngine", new HookLuaToOns());
            e.OnRaw.Add("LuaEngine", new HookLuaToOns());
            e.Aliases.Add("loadlua", new LuaEngine.ALoadScript());
            e.Aliases.Add("unloadlua", new LuaEngine.AUnloadScript());
            e.Aliases.Add("exelua", new LuaEngine.AExecuteAlias());
            ToolStripMenuItem m = new ToolStripMenuItem("Lua Console");
            m.Click += new EventHandler(m_Click);
            e.ToolsAddinsMenu.DropDownItems.Add(m);
        }

        void m_Click(object sender, EventArgs e)
        {
            new LuaConsole().Show(ex.Panel);
        }

        #endregion
    }

    public class LuaEngine
    {
        public Dictionary<string, string> LuaScripts = new Dictionary<string, string>();
        public Dictionary<string, string> On = new Dictionary<string, string>();
        public Dictionary<string, string> Alias = new Dictionary<string, string>();

        public LuaHook TheLuaHook;
        ExtencibilityManager ex;

        public LuaEngine(ExtencibilityManager e) { ex = e; TheLuaHook = new LuaHook(ex); }

        public void LoadScript(string fileName, string name)
        {
            if ((name != null) && (name != ""))
            {
                LuaScripts.Add(name, fileName);
                TheLuaHook.GetLuaEngine(null).DoString(File.ReadAllText(LuaScripts[name]) + Environment.NewLine + "on_load()");
            }
            else
            {
                throw new Exception("Missing Name Attribute");
            }
        }

        public void UnloadScript(string name)
        {
            TheLuaHook.GetLuaEngine(null).DoString(File.ReadAllText(LuaScripts[name]) + Environment.NewLine + "on_unload()");
            LuaScripts.Remove(name);
        }

        public class ALoadScript : Alias
        {
            #region Alias Members

            public void Execute(string[] args, Dictionary<string, string> vars, ExtencibilityManager ex)
            {
                Plugin.engine.LoadScript(String.Join(" ", args).Remove(0, args[0].Length).Remove(0, args[1].Length).Remove(0, args[2].Length).Remove(0, 3), args[2]);
            }

            #endregion
        }

        public class AUnloadScript : Alias
        {
            #region Alias Members

            public void Execute(string[] args, Dictionary<string, string> vars, ExtencibilityManager ex)
            {
                Plugin.engine.UnloadScript(args[2]);
            }

            #endregion
        }

        public class AExecuteAlias : Alias
        {
            #region Alias Members

            public void Execute(string[] args, Dictionary<string, string> vars, ExtencibilityManager ex)
            {
                foreach (KeyValuePair<string, string> i in Plugin.engine.Alias)
                {
                    if (i.Key == args[2])
                    {
                        foreach (KeyValuePair<string, string> j in Plugin.engine.LuaScripts)
                        {
                            Dictionary<string, string> d = new Dictionary<string, string>();
                            d.Add("args", String.Join(" ", args));
                            Plugin.engine.TheLuaHook.GetLuaEngine(d).DoString(File.ReadAllText(Plugin.engine.LuaScripts[j.Key]) + Environment.NewLine + i.Value + "()");
                        }
                    }
                }
            }

            #endregion
        }

    }

    public class LuaHook
    {
        ExtencibilityManager ex;

        public LuaHook(ExtencibilityManager e) { ex = e; }

        public LuaInterface.Lua GetLuaEngine(Dictionary<string, string> dict)
        {
            LuaInterface.Lua engine = new LuaInterface.Lua();
            if (dict != null)
            {
                foreach (KeyValuePair<string, string> i in dict)
                {
                    engine[i.Key] = i.Value;
                }
            }
            engine.RegisterFunction("Shion_MessageBox", this, GetType().GetMethod("Shion_MessageBox"));
            engine.RegisterFunction("Shion_OnHook", this, GetType().GetMethod("Shion_OnHook"));
            engine.RegisterFunction("Shion_DeHook", this, GetType().GetMethod("Shion_DeHook"));
            engine.RegisterFunction("Shion_OnAliasHook", this, GetType().GetMethod("Shion_OnAliasHook"));
            engine.RegisterFunction("Shion_DeAliasHook", this, GetType().GetMethod("Shion_DeAliasHook"));
            engine.RegisterFunction("Shion_SendMessage", this, GetType().GetMethod("Shion_SendMessage"));
            engine.RegisterFunction("Shion_SendAction", this, GetType().GetMethod("Shion_SendAction"));
            engine.RegisterFunction("Shion_SendNotice", this, GetType().GetMethod("Shion_SendNotice"));
            engine.RegisterFunction("Shion_Address", this, GetType().GetMethod("Shion_Address"));
            engine.RegisterFunction("Shion_Echo", this, GetType().GetMethod("Shion_Echo"));
            engine.RegisterFunction("Shion_SendRaw", this, GetType().GetMethod("Shion_SendRaw"));
            engine.RegisterFunction("Shion_Timer", this, GetType().GetMethod("Shion_Timer"));
            engine.RegisterFunction("Shion_ExecuteCmd", this, GetType().GetMethod("Shion_ExecuteCmd"));
            
            return engine;
        }

        public void Shion_MessageBox(string message) 
        {
            MessageBox.Show(message, "Shion 6 Lua Engine", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        public void Shion_OnHook(string onString, string function) 
        {
            Plugin.engine.On.Add(onString, function);
        }
        public void Shion_DeHook(string onString) 
        {
            Plugin.engine.On.Remove(onString);
        }
        public void Shion_OnAliasHook(string onString, string function)
        {
            Plugin.engine.Alias.Add(onString, function);
        }
        public void Shion_DeAliasHook(string onString)
        {
            Plugin.engine.Alias.Remove(onString);
        }
        public void Shion_SendMessage(string server, string channel, string message) 
        {
            ex.Clients[server].SendMessage(SendType.Message, channel, message);
        }
        public void Shion_SendAction(string server, string channel, string message)
        {
            ex.Clients[server].SendMessage(SendType.Action, channel, message);
        }
        public void Shion_SendNotice(string server, string channel, string message)
        {
            ex.Clients[server].SendMessage(SendType.Notice, channel, message);
        }
        public void Shion_Echo(string server, string message) 
        {
            ex.ConsoleWrite(server, message);
        }
        public void Shion_ExecuteCmd(string server, string cmd)
        {
            Executer.Execute(ex, cmd, server);
        }
        public string Shion_Address(string server, string nick, int mode)
        {
            return ex.Address(server, nick, mode);
        }
        public void Shion_SendRaw(string server, string raw) 
        {
            ex.Clients[server].WriteLine(raw);
        }
        public void Shion_Timer(string server, string command, int times, int milliseconds)
        {
            new ShionTimer(ex, command, times, milliseconds, server);
        }
    }

    public class HookLuaToOns : OnRaw, OnCommand
    {
        #region OnRaw Members

        public void Execute(NasuTek.Shion.Agent.IrcEventArgs e, ExtencibilityManager em)
        {
            foreach (KeyValuePair<string, string> i in Plugin.engine.LuaScripts)
            {
                foreach (KeyValuePair<string, string> ls in Plugin.engine.On)
                {
                    string[] p = ls.Key.Split(':');
                    if (p[0] == "RAW")
                    {
                        if (Regex.IsMatch(Convert.ToInt32(e.Data.ReplyCode).ToString(), p[1]))
                        {
                            Plugin.engine.TheLuaHook.GetLuaEngine(null).DoString(File.ReadAllText(i.Value) + Environment.NewLine + ls.Value);
                        }
                    }
                }
            }
        }

        #endregion

        #region OnCommand Members

        public void Execute(string[] args, Dictionary<string, string> vars, ExtencibilityManager ex, NasuTek.Shion.Agent.IrcEventArgs ea)
        {
            if (ea.Data.RawMessageArray[1] == "PRIVMSG")
            {
                foreach (KeyValuePair<string, string> i in Plugin.engine.LuaScripts)
                {
                    foreach (KeyValuePair<string, string> ls in Plugin.engine.On)
                    {
                        string[] p = ls.Key.Split(':');
                        if (p[0] == "TEXT")
                        {
                            if (Regex.IsMatch(ea.Data.Message, p[1]))
                            {
                                Plugin.engine.TheLuaHook.GetLuaEngine(vars).DoString(File.ReadAllText(i.Value) + Environment.NewLine + ls.Value + "()");
                            }
                        }
                        if (p[0] == "ACTION")
                        {
                            if (ea.Data.Message.Contains("\x1" + "ACTION"))
                            {
                                if (Regex.IsMatch(ea.Data.Message.Replace("\x1" + "ACTION", "").Replace("\x1", ""), p[1]))
                                {
                                    Plugin.engine.TheLuaHook.GetLuaEngine(vars).DoString(File.ReadAllText(i.Value) + Environment.NewLine + ls.Value + "()");
                                }
                            }
                        }
                    }
                }
            }
            else if (ea.Data.RawMessageArray[1] == "NOTICE")
            {
                foreach (KeyValuePair<string, string> i in Plugin.engine.LuaScripts)
                {
                    foreach (KeyValuePair<string, string> ls in Plugin.engine.On)
                    {
                        string[] p = ls.Key.Split(':');
                        if (p[0] == "NOTICE")
                        {
                            if (Regex.IsMatch(ea.Data.Message, p[1]))
                            {
                                Plugin.engine.TheLuaHook.GetLuaEngine(vars).DoString(File.ReadAllText(i.Value) + Environment.NewLine + ls.Value);
                            }
                        }
                    }
                }
            }
        }

        #endregion
    }

   
}
